package com.codi.api.controller.h5;

import com.codi.api.validation.TradeValidation;
import com.codi.base.cache.CacheUtil;
import com.codi.base.exception.BaseAppException;
import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.*;
import com.codi.base.web.RequestUtils;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.domain.Lookup;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.*;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.bus.core.util.BaseResultUtil;
import com.codi.bus.core.vo.BuyVo;
import com.codi.bus.util.LookupUtil;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: zengxl
 * @Description: 瑞富宝相关控制类
 * @Date:2018/3/8 13:48
 */
@RestController
@Slf4j
@RequestMapping("/h5/ruifubao")
public class H5RuifubaoController {
    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;
    @Resource(name = "userService")
    private UserService userService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private QueryService queryService;
    @Autowired
    private PaperInfoService paperInfoService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private TradeValidation tradeValidation;
    @Resource(name = "tradeService")
    private TradeService tradeService;
    @Autowired
    private BranchBankService branchBankService;
    @Autowired
    private LookupService lookupService;
    @Autowired
    private DividendApplyService dividendApplyQuery;
    @Autowired
    private ApplyRecordService applyRecordService;
    @Autowired
    private T0Service t0Service;

    /**
     * 瑞富宝--详情界面
     *
     * @param fundCode 货币基金代码
     * @return
     * @throws BaseAppException
     * @author mifj
     */
    @GetMapping("/detail")
    @Loggable
    public WalletDetailResult detail(@RequestParam("fundCode") String fundCode, HttpServletRequest request) throws BaseAppException {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            WalletDetailResult result = walletService.getWalletDetailByFundCode(userId, fundCode);
            //设置推荐基金
            result.setRecommendedFundModel(queryService.queryRecommendedFund());
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("h5接口:/h5/ruifubao/detail?fundcode={},错误信息:{}", fundCode, e.getMessage());
        }

        return null;
    }


    /**
     * 获取用户的零钱包操作记录, 因为恒生方面原因, 当前默认获取所有的零钱包交易记录, 后期可能会根据需求进行改造, 例如: 一定时间?
     *
     * @author mifj
     * @since hzren
     */
    @GetMapping("/record")
    @Loggable
    public ResponseEntity<?> record(HttpServletRequest request, @RequestParam(defaultValue = "") String fundCode) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        int requestNum = GlobalConstant.MAX_REQUEST_NUM;
        int queryFlag = 1;
        int beginNum = 1;
        String sortDirection = "0";
        try {
            return new ResponseEntity<>(
                queryService.queryWalletOperationList(
                    userId,
                    requestNum,
                    queryFlag,
                    beginNum,
                    sortDirection,
                    fundCode
                ),
                HttpStatus.OK);
        } catch (Exception e) {
            log.error("h5接口:/h5/ruifubao/record?fundCode={} 错误信息:{}", fundCode, e.getMessage());
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 资产--瑞富宝交易记录
     *
     * @param fundCode  瑞富宝代码 非必
     * @param queryType 业务类型, all 全部 onWay 进行中
     * @return
     */
    @GetMapping("/ruifubaoRecord")
    @Loggable
    public BaseResult ruifubaoRecord(HttpServletRequest request, String fundCode, @NonNull String queryType, String business, Integer requestNum, Integer beginNum, String allotNo) {
        WTradingRecordListResult wTradingRecordListResult = null;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            wTradingRecordListResult = applyRecordService.queryRuifubaoRecord(fundCode, queryType, userId, beginNum, requestNum, business, allotNo);
        } catch (Exception e) {
            ExceptionUtil.logError(log, "ruifubaoRecord - Exception:", e);
        }
        return wTradingRecordListResult;
    }

    /**
     * 瑞富宝--详情界面--买入
     * 对风险评测进行了修改
     * 不知道机构是否调用
     *
     * @param request
     * @param fundCode 基金代码
     * @return
     */
    @GetMapping("goBuy")
    @Loggable
    public CheckResult goBuy(HttpServletRequest request, @RequestParam String fundCode) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        CheckResult result = new CheckResult();
        User userEntity = userService.getUser(userId);
        if (userEntity == null) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_USER_FIND);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_NO_USER_FIND));
            return result;
        }
        result.setSuccess(true);
        String externalClientId = userEntity.getExternalClientId();
        if (StringUtil.isEmpty(externalClientId)) {
            // 未开户
            result.setStatus(1);
            return result;
        } else {
            // 获取用户银行卡
            BaseListResult listResult = queryService.queryAccountBanks("", userEntity.getExternalClientId(), "",
                GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1");
            if (!listResult.getSuccess()) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_NO_BANK_CARD_FIND));
                return result;
            }
            List<BankModel> banks = ((BankListResult) listResult).getBanks();
            if (banks == null || banks.size() == 0) {
                // 未开户
                result.setStatus(1);
                return result;
            } else {
                // 判断是否开户
                boolean isOpen = false;
                for (BankModel bankModel : banks) {
                    if (!StringUtil.isEmpty(bankModel.getCapitalMode()) && !bankModel.getCapitalMode().equals(GlobalConstant.CAPITAL_MODE_COUNTER)) {
                        isOpen = true;
                        break;
                    }
                }
                if (!isOpen) {
                    // 未开户
                    result.setStatus(1);
                    return result;
                } else {
                    //判断是否已在私募入口做过风险测评，如果已做过，则传入之前的风险测评结果
                    PaperInfoTestResult privateResult = paperInfoService.getUserPaperInfoTestResult(userId, "", null);

                    if (privateResult.isHave_tested()) {
                        String expireDate = privateResult.getExpire_date();
                        Date now = new Date();
                        Date expire = DateUtil.parse(expireDate);
                        if (now.after(expire)) {
                            //风险评测过期
                            result.setStatus(3);
                            return result;
                        } else {
                            //查询个人的风险评测等级
                            result.setStatus(0);
                            BaseResult baseResult = paymentService.getPayMethodsForWallet(userId);
                            if (baseResult.getResult() == null) {
                                result.setSuccess(false);
                                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                                result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_NO_BANK_CARD_FIND));
                                return result;
                            } else {

                                ShareTypeModel shareTypeModel = queryService.getShareType(fundCode);
                                if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
                                    result.setSuccess(false);
                                    result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
                                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                                    result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
                                    return result;
                                }
                                String shareType = shareTypeModel.getShareType();
                                String custType = userEntity.getIsOrg() ? GlobalConstant.CUST_TYPE_ORGANIZATION : GlobalConstant.CUST_TYPE_PERSONAL;
                                TradeLimitListResult limitListResult = queryService.queryTradeLimits(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", fundCode, shareType,
                                    GlobalConstant.CAPITAL_MODE_EPAY, "022", custType);
                                if (limitListResult.getSuccess() == false) {
                                    result.setSuccess(false);
                                    result.setErrorCode(limitListResult.getErrorCode());
                                    result.setErrorType(limitListResult.getErrorType());
                                    result.setErrorMessage(MessageUtil.getErrorMessage(limitListResult.getErrorCode(), null));
                                    return result;
                                }
                                Map<String, String> userInv = Maps.newHashMap();
                                userInv.put("userRisk", privateResult.getInvest_risk_tolerance());
                                userInv.put("userRiskDesc", privateResult.getInvest_risk_tolerance_desc());
                                Map<String, Object> resultMap = Maps.newHashMap();
                                resultMap.put("payWay", baseResult.getResult());
                                resultMap.put("limits", limitListResult.getLimits());
                                resultMap.put("userInv", userInv);
                                result.setResult(resultMap);
                                return result;
                            }
                        }
                    } else {
                        //未做风险评测
                        result.setStatus(2);
                        return result;
                    }
                }
            }
        }
    }

    /**
     * @param request
     * @param buyVo   payType=选择的支付方式  fundCode=基金代码 fundName=基金名称
     *                fundBalance=买入金额 tradeAcco=选择支付方式的交易账号
     *                applyNo=前端根据当前时间自动生成，格式：yyyyMMddHHmmssSSS
     *                tradePassword=交易密码 sign=随机生成，不为空，无意义
     * @return
     */
    @PostMapping("sureBuy")
    @Loggable
    public BaseResult sureBuy(HttpServletRequest request, @Validated BuyVo buyVo) {
        BaseResult result = null;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        buyVo.setUserId(userId);
        buyVo.setChannelId(chanelCode);
        buyVo.setMoneyType(GlobalConstant.MONEY_TYPE_RMB);
        // 验证输入
        result = tradeValidation.validateBuy(buyVo);
        if (result != null) {
            return result;
        }
        // 调用接口
        result = tradeService.buy(buyVo);
        BaseResultUtil.parseErrMsg(result);
        return result;
    }

    @GetMapping("withdraw")
    @Loggable
    public BaseResult withdraw(HttpServletRequest request, @RequestParam String fundCode) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        CashChangeListResult result = walletService.getWalletCashChangeDetails(userId, fundCode);
        return result;
    }

    /**
     * 瑞富宝--详情界面--提现确认
     *
     * @param request
     * @param bankAccount   提现银行账号
     * @param fundName      基金名称
     * @param fundCode      基金代码
     * @param shares        提现金额
     * @param tradePassword 交易密码
     * @param applyNo       申请号，自动生成，格式：yyyyMMddHHmmssSSS
     * @param vcBranchbank  支行
     * @param vcBankname    支行名称
     * @param withdrawType  赎回方式 1=快速赎回  2=普通赎回
     * @return
     */
    @PostMapping("sureWithdraw")
    @Loggable
    public BaseResult sureWithdraw(HttpServletRequest request, @RequestParam String bankAccount, @RequestParam String fundName,
                                   @RequestParam String fundCode, @RequestParam BigDecimal shares, @RequestParam String tradePassword,
                                   @RequestParam String applyNo, @RequestParam String vcBranchbank, @RequestParam String vcBankname,
                                   @RequestParam String withdrawType) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        BaseResult result = new BaseResult();
        result.setSuccess(false);
        User user = userService.getUser(userId);
        if (user == null) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "用户ID错误");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(withdrawType)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "赎回方式");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        boolean isOrg = user.getIsOrg();

        String paymentType = GlobalConstant.CAPITAL_MODE_EPAY;

        if (StringUtil.isEmpty(bankAccount)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "银行账号");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(fundName)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "基金名称");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(fundCode)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "基金代码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(tradePassword)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "交易密码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (MoneyUtils.compareTo(shares, 0) != 1) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "赎回份额");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        // 验证是否重复提交, 5分钟过期
        applyNo = applyNo + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);
        // 获取份额类别
        ShareTypeModel shareTypeModel = queryService.getShareType(fundCode);
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }
        String shareType = shareTypeModel.getShareType();

        if ("2".equals(withdrawType)) {//普通赎回
            if (isOrg) {//机构
                paymentType = GlobalConstant.CAPTIAL_MODE_K;
                Boolean orgAcctIsOpen = userService.checkOrgAcctIsOpen(userId);
                if (!orgAcctIsOpen) {
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC);
                    result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC));
                    return result;
                }
            } else {//个人
                if (StringUtil.isEmpty(vcBranchbank)) {
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
                    Map<String, String> map = new HashMap<>();
                    map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "支行信息");
                    result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
                    return result;
                }
                //先验证支行修改是否成功
                result = branchBankService.setBranchBank(userId, vcBranchbank, vcBankname, tradePassword);
                if (!result.getSuccess()) {
                    return result;
                }
            }
            //发起赎回交易
            result = tradeService.sellReal(userId, chanelCode, bankAccount, paymentType, fundName, fundCode,
                shares, shareType, tradePassword, applyNo);
            if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
                result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
            }
            return result;
        } else if ("1".equals(withdrawType)) {//快速赎回
            String brandsType = FundUtil.getT0FundBrandsType(fundCode);
            if (isOrg) {
                if (lookupService.isT0Fund(fundCode)) {
                    // 如果是机构用户，宝盈不支持快速赎回 shi.pengyan 2017-10-11 10:24:07
                    if (FundUtil.isBaoYingT0AB(fundCode)) {
                        result.setErrorCode(ErrorConst.COMMON_USER_PERMISSION_ONLY);
                        result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.COMMON_USER_PERMISSION_ONLY));
                        result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                        return result;
                    }
                    // 金鹰T+0, 机构快速赎回时间为每天8:35-17:00，其余时间只能进行普通赎回
                    if (FundUtil.isJinYingT0AB(fundCode)) {
                        String startTimeStr = lookupService.getLookup(RuleConstant.T0FUND_JINYING_START_TIME).getRuleValue();
                        String endTimeStr = lookupService.getLookup(RuleConstant.T0FUND_JINYING_END_TIME).getRuleValue();

                        Boolean isInRange = TimeUtil.nowIsInRange(startTimeStr + ":00", endTimeStr + ":00", TimeUtil.FORMAT_HHmmSS);

                        if (!isInRange) {
                            String errorMsg = MessageUtil.getErrorMsg(ErrorConst.ORGAN_FASTREDEEM_JINYING_NOT_IN_SUPPORT_TIME
                                , startTimeStr, endTimeStr);
                            result.setErrorCode(ErrorConst.ORGAN_FASTREDEEM_JINYING_NOT_IN_SUPPORT_TIME);
                            result.setErrorMessage(errorMsg);
                            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                            return result;
                        }
                    }

                    // 长城T+0, 机构快速赎回时间为每天8:35-17:00，其余时间只能进行普通赎回
                    if (FundUtil.isChangChengT0AB(fundCode)) {
                        String startTimeStr = lookupService.getLookup(RuleConstant.T0FUND_CHANGCHENG_START_TIME).getRuleValue();
                        String endTimeStr = lookupService.getLookup(RuleConstant.T0FUND_CHANGCHENG_END_TIME).getRuleValue();
                        Boolean isInRange = TimeUtil.nowIsInRange(startTimeStr + ":00", endTimeStr + ":00", TimeUtil.FORMAT_HHmmSS);
                        if (!isInRange) {
                            String errorMsg = MessageUtil.getErrorMsg(ErrorConst.ORGAN_FASTREDEEM_CHANGCHENG_NOT_IN_SUPPORT_TIME
                                , startTimeStr, endTimeStr);
                            result.setErrorCode(ErrorConst.ORGAN_FASTREDEEM_CHANGCHENG_NOT_IN_SUPPORT_TIME);
                            result.setErrorMessage(errorMsg);
                            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                            return result;
                        }
                    }


                }
            }

            boolean hasDayDealLimit = false, hasDayDealCountLimit = false;
            //宝盈T+0：
            // 个人用户快赎：单笔限额5万，单日上限200万，次数不限；
            // 机构不支持快赎；

            // 金鹰T+0 长城t+0
            // a) 个人用户快赎：单笔限额200万，单日上限200万，单日次数限制10次
            // b) 机构用户快赎：单笔限额1000万，单日上限5000万，单日次数限制5次
            if (FundUtil.isBaoYingT0AB(fundCode) || FundUtil.isJinYingT0AB(fundCode) ||
                FundUtil.isChangChengT0AB(fundCode)) {

                String str;
                Lookup lookup;

                if (FundUtil.isBaoYingT0AB(fundCode)) {
                    lookup = lookupService.getLookup(RuleConstant.T0FUND_BAOYING_CONFIG);
                } else {
                    lookup = lookupService.getLookup(RuleConstant.RULE_LOOKUP_TYPE_T0FUND, fundCode);
                }

                str = lookup.getComponentValue();

                //TODO 单笔限额
                String maxSingleDealStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(),
                    RuleConstant.FIELD_SINGLE_DEAL_LIMIT);
                if (StringUtil.isNotEmpty(maxSingleDealStr)) {
                    if ("-1".equals(maxSingleDealStr)) { // 不做校验
                    } else {
                        if (shares.compareTo(new BigDecimal(maxSingleDealStr)) > 1) {
                            String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_SINGLE_DEAL
                                , maxSingleDealStr);
                            result.setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_SINGLE_DEAL);
                            result.setErrorMessage(errorMsg);
                            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                            return result;
                        }
                    }
                }

                //TODO 单日上限
                String maxDayDealStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);
                if (StringUtil.isNotEmpty(maxDayDealStr)) {
                    if ("-1".equals(maxDayDealStr)) {// 不做校验
                    } else {
                        hasDayDealLimit = true;
                        BigDecimal currentDayDeal = walletService.getFastRedeemDayUsedMoney(userId, brandsType);
                        BigDecimal finalDeal = currentDayDeal.add(shares);
                        if (finalDeal.compareTo(new BigDecimal(maxDayDealStr)) > 1) {
                            String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_DAY_DEAL
                                , maxDayDealStr);
                            result.setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_DAY_DEAL);
                            result.setErrorMessage(errorMsg);
                            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                            return result;
                        }

                    }
                }

                //TODO 单日交易限制次数
                String maxDayDealCountStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(),
                    RuleConstant.FIELD_DAY_DEAL_COUNT_LIMIT);

                if (StringUtil.isNotEmpty(maxDayDealCountStr)) {
                    if ("-1".equals(maxDayDealCountStr)) { // 不做校验
                    } else {
                        hasDayDealCountLimit = true;
                        int currentCount = walletService.getFastRedeemCountInCurrentDay(userId, brandsType);
                        if (currentCount >= Integer.valueOf(maxDayDealCountStr)) {
                            String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_REDEEM_TIME);
                            result.setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_REDEEM_TIME);
                            result.setErrorMessage(errorMsg);
                            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                            return result;
                        }
                    }
                }

            }
            // 调用接口
            result = tradeService.fastRedeemReal(userId, chanelCode, paymentType, tradePassword, fundCode,
                shareType, shares, bankAccount, fundName, applyNo);

            // 失败
            if (!result.getSuccess()) {
                if (StringUtil.isEmpty(result.getErrorMessage())) {
                    result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
                }
            } else {
                if (FundUtil.isJinYingT0AB(fundCode) || FundUtil.isChangChengT0AB(fundCode)) {
                    if (hasDayDealCountLimit) { // 增加交易次数
                        walletService.increaseFastRedeemCountInCurrentDay(userId, brandsType);
                    }
                    if (hasDayDealLimit) { // 增加交易金额
                        walletService.increaseFastRedeemDayUsedMoney(userId, brandsType, shares);
                    }
                }
            }
            return result;
        } else {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage("不支持的赎回方式");
            return result;
        }
    }

    /**
     * 瑞富宝--撤单
     *
     * @param request
     * @param allotNo       源交易申请编号
     * @param tradePassword 交易密码
     * @param applyNo       客户端自动生成，格式：yyyyMMddHHmmssSSS
     * @return
     */
    @PostMapping("undo")
    @Loggable
    public BaseResult undo(HttpServletRequest request, @RequestParam String allotNo, @RequestParam String tradePassword, @RequestParam String applyNo) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        BaseResult result = new BaseResult();
        result.setSuccess(false);
        if (StringUtil.isEmpty(tradePassword)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "交易密码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }

        if (StringUtil.isEmpty(allotNo)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "申请编号");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        // 验证是否重复提交, 5分钟过期
        applyNo = applyNo + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        User user = userService.getUser(userId);
        if (user == null) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_SYS_EXCEPTION);
            return result;
        }
        if (user.getIsOrg()) {//机构撤单，再去验证机构有没有开户
            Boolean orgAcctIsOpen = userService.checkOrgAcctIsOpen(userId);
            if (!orgAcctIsOpen) {
                result = new BaseResult(false);
                result.setErrorCode(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC);
                result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC));
                return result;
            }
        }
        result = tradeService.undoReal(userId, chanelCode, allotNo, tradePassword, user.getIsOrg());
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;
    }

    /**
     * 瑞富宝分红交易记录
     */
    @GetMapping("/dividend/apply")
    @Loggable
    public BaseResult dividendApply(@RequestParam Integer requestNum,
                                    @RequestParam Integer queryFlag,
                                    @RequestParam Integer beginNum,
                                    @RequestParam String sortDirection, HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String taSerialId = null;
        DividendApplyResult result = dividendApplyQuery.queryWalletDividendApplys(userId, requestNum, queryFlag, beginNum,
            sortDirection, taSerialId);
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;
    }

    /**
     * 查询t0列表降序--区分收益结算方式
     *
     * @param fundReport 基金结算方式 R：收益日结转 Y：收益月结转
     * @return
     */
    @Loggable
    @GetMapping("/t0_funds_report")
    @ResponseBody
    public BaseResult getT0ReportList(@RequestParam String fundReport, HttpServletRequest request) {
        BaseResult result = new BaseResult();
        if (!"R".equals(fundReport) && !"Y".equals(fundReport)) {
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorMessage("参数错误");
            return result;
        }

        boolean isOrg = false;

        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        if (userId != null) {
            User user = userService.getUser(userId);
            if (user.getIsOrg()) {
                isOrg = true;
            }
        }
        Lookup lookup = lookupService.getLookup(RuleConstant.T0FUND_LIST_DISPLAY_FUNDS);

        List<T0Model> data;

        if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) { // 使用
            String valueStr = lookup.getRuleValue();
            String[] fundCodeArray = valueStr.split(",");

            data = t0Service.queryT0Funds(isOrg, Arrays.asList(fundCodeArray));
        } else { // 不是用
            data = t0Service.queryT0Funds(isOrg);
        }
        List<T0Model> returnList = Lists.newArrayList();
        for (T0Model model : data) {
            if (fundReport.equals(model.getFundReport())) {
                returnList.add(model);
            }
        }
        return result.setSuccess(true).setResult(returnList);
    }

    /**
     * 赎回转购 瑞富宝 推荐
     *
     * @param balance
     * @return
     */
    @GetMapping("/recommend")
    @Loggable
    public BaseResult getRecommend(String balance) {
        BigDecimal balance2 = new BigDecimal(balance);

        log.debug("balance:{}", balance);
        log.debug("balance2:{}", balance2);

        RecommendResult recommendResult = new RecommendResult();
        FundModel fundModelE = queryService.queryFund(GlobalConstant.T0_FUND_CHANGCHENG_E);
        FundModel fundModelA = queryService.queryFund(GlobalConstant.T0_FUND_JINYING2_A);

        if (balance2.compareTo(new BigDecimal(GlobalConstant.WUBAIWAN)) >= 0 && fundModelE.getCanBuy() || !fundModelA.getCanBuy()) {
            recommendResult.setFundCode(GlobalConstant.T0_FUND_CHANGCHENG_E);
            recommendResult.setFundName(GlobalConstant.T0_FUND_CHANGCHENG_E_NAME);
        } else {
            recommendResult.setFundCode(GlobalConstant.T0_FUND_JINYING2_A);
            recommendResult.setFundName(GlobalConstant.T0_FUND_JINYING2_A_NAME);


            List<TradeLimitModel> tradeLimitModels = queryService.queryTradeLimits(GlobalConstant.T0_FUND_JINYING2_A, true);

            // 最小申购
            if (tradeLimitModels != null) {
                for (TradeLimitModel model : tradeLimitModels) {
                    if ("022".equals(model.getFundBusinCode())) {
                        recommendResult.setMinPurchase(model.getMinValue());
                    }
                }
            }
        }

        return new BaseResult().setResult(recommendResult);
    }


    /**
     * 赎回转购文案
     *
     * @return
     */
    @GetMapping("/sellToWalletString")
    @ResponseBody
    public BaseResult getSellToWalletString(HttpServletRequest request) {
        String fundReport = "R";
        String resultStr = "可享受瑞富宝收益，七日年化收益";
        BaseResult result = new BaseResult();

        boolean isOrg = false;

        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        if (userId != null) {
            User user = userService.getUser(userId);
            if (user.getIsOrg()) {
                isOrg = true;
            }
        }
        Lookup lookup = lookupService.getLookup(RuleConstant.T0FUND_LIST_DISPLAY_FUNDS);

        List<T0Model> data;

        if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) { // 使用
            String valueStr = lookup.getRuleValue();
            String[] fundCodeArray = valueStr.split(",");

            data = t0Service.queryT0Funds(isOrg, Arrays.asList(fundCodeArray));
        } else { // 不是用
            data = t0Service.queryT0Funds(isOrg);
        }
        List<T0Model> returnList = Lists.newArrayList();
        for (T0Model model : data) {
            if (fundReport.equals(model.getFundReport())) {
                returnList.add(model);
            }
        }

        List<String> t0Vo = new ArrayList<>();
        returnList.forEach(t0Model -> {
            t0Vo.add(t0Model.getLatestWeeklyYieldStr());
        });
        t0Vo.sort(String::compareTo);
        String number = t0Vo.get(0) + "%~" + t0Vo.get(t0Vo.size() - 1) + "%";
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("title", resultStr);
        resultMap.put("number", number);
        result.setResult(resultMap);
        return result;
    }


    /**
     * 瑞富宝列表,日结转
     *
     * @return
     */
    @GetMapping("/sellForWalletChoose")
    public BaseResult sellForWalletChoose() {
        String fundReport = "R";
        BaseResult result = new BaseResult();
        Lookup lookup = lookupService.getLookup(RuleConstant.T0FUND_LIST_DISPLAY_FUNDS);
        List<T0Model> data;
        if (EqualsUtil.equals(1, lookup.getRuleStatus().intValue())) {
            String valueStr = lookup.getRuleValue();
            String[] fundCodeArray = valueStr.split(",");
            data = t0Service.queryT0Funds(true, Arrays.asList(fundCodeArray));
        } else {
            data = t0Service.queryT0Funds(true);
        }
        data = data.stream().filter(t0Model -> fundReport.equals(t0Model.getFundReport())).collect(Collectors.toList());

        data.forEach(t0Model -> {
            FundModel fundModel = queryService.queryFund(t0Model.getFundCode());
            boolean canBuy = fundModel.getCanBuy();
            t0Model.setCanBuy(canBuy);
        });

        result.setResult(data);
        return result;
    }


}
